﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace TanksDesk
{
    public partial class FrmShot : Form
    {
        int xCntr;
        int yCntr;
        int DiamCockshot; // диаметр мишени
        int DiamAll;// диаметр общей зоны поражения
        double Step;

        DateTime dtStart;

        int[] ret;

        public FrmShot()
        {
            InitializeComponent();
            im.Image = new Bitmap(im.Width, im.Height);
            xCntr = im.Width / 2;
            yCntr = im.Height / 2;
            DiamAll = im.Width - 10;
        }

        int AppleHit;
        int KolVoDarts;
        Point[] pShots;
        int ActShot = 0;

        // зона мишени (значение от 1% до 100%. 100% - зона мишени занимает все пространство)
        // количество дротиков
        // значение яблочка

        public int[] ShowDialog(int CockshotPercent, int AppleHit, int KolVoDarts)
        {
            this.AppleHit = AppleHit;
            this.KolVoDarts = KolVoDarts;
            DiamCockshot = (int)(DiamAll / 100.0 * CockshotPercent);
            Step = DiamCockshot / ((double)AppleHit * 2.0);
            pShots = new Point[KolVoDarts];
            for (int i = 0; i < KolVoDarts; i++) pShots[i] = new Point(int.MinValue, int.MinValue);
            ActShot = 0;
            ret = new int[KolVoDarts];
            ShowDialog();

            return ret;
        }

        private void FrmShot_Shown(object sender, EventArgs e)
        {
            if (Form1.IsTestShot)
            {
                //подсчет процента попадания в каждое поле
                int[] hl = new int[AppleHit + 1];
                int actHits = 0;
                int kolVoTry = 300000;
                for (int i = 0; i < kolVoTry; i++)
                {
                    actHits = GetShot();
                    hl[actHits]++;
                    ret[0] = actHits;
                }

                ReDraw();

                string s = "";
                for (int i = 0; i < hl.Length; i++)
                {
                    s += i.ToString() + ": " + Math.Round(hl[i] / (double)kolVoTry * 100, 0).ToString() + "%\r\n";
                }
                MessageBox.Show(s);
            }
            else
            {
                dtStart = DateTime.Now;
                tmrShot.Start();
                ReDraw();
            }
        }

        void ReDraw()
        {
            Graphics gr = Graphics.FromImage(im.Image);
            gr.Clear(Color.White);

            DrawTarget(gr);
            for (int i = 0; i < KolVoDarts; i++) if (pShots[i].X != int.MinValue) DrawShot(gr, pShots[i], ret[i]);

            gr.DrawEllipse(Pens.LightGray, xCntr - DiamAll / 2, yCntr - DiamAll / 2, DiamAll, DiamAll);

            gr.Dispose();
            im.Refresh();
        }

        Font fnt = new Font("Arial", 12, FontStyle.Bold);

        void DrawTarget(Graphics gr)
        {
            gr.FillEllipse(Brushes.Wheat, xCntr - DiamCockshot / 2, yCntr - DiamCockshot / 2, DiamCockshot, DiamCockshot);

            for (int i = 0; i < AppleHit; i++)
            {
                int radius = (int)(Step * (i + 1));
                gr.DrawEllipse(Pens.Black, xCntr - radius, yCntr - radius, radius * 2, radius * 2);

                int yStr = yCntr - radius + (int)(Step / 2) - 8;
                if (i == 0) yStr = yCntr - 8;

                gr.DrawString((AppleHit - i).ToString(), fnt, Brushes.Black, xCntr - 5, yStr);

            }
        }

        Font fntShot = new Font("Arial", 12, FontStyle.Bold);

        Pen pnShot = new Pen(Color.Maroon, 3);

        void DrawShot(Graphics gr, Point pShot, int val)
        {
            gr.FillEllipse(Brushes.Blue, pShot.X - 5, pShot.Y - 5, 10, 10);
            gr.DrawLine(pnShot, pShot.X - 8, pShot.Y - 8, pShot.X + 8, pShot.Y + 8);
            gr.DrawLine(pnShot, pShot.X + 8, pShot.Y - 8, pShot.X - 8, pShot.Y + 8);

            gr.DrawString(val.ToString(), fnt, Brushes.Red, pShot.X + 8, pShot.Y - 8);

        }

        Random rnd = new Random();

        int GetShot()
        {
            int numHit = GenerateNumShot3(out pShots[ActShot]);
            return numHit;
        }

        int GenerateNumShot1(out Point pnt)
        {
            // вычисляем общую площадь цели
            // выбираем случайное число из этой площали
            // смотрим, в какую площадь от самого внутреннего круга попало число
            int S = (int)Math.Pow(Math.PI * DiamAll / 2, 2);
            int rndS = rnd.Next(S);

            // минимальный и максимальный радиусы, чтобы отобразить попадание в цель
            int minRadius = 0;
            int maxRadius = (int)Step;
            int numHit = AppleHit;
            bool bHit = false;

            // смотрим попадание
            for (int i = 0; i < AppleHit; i++)
            {
                minRadius = (int)(Step * i);
                maxRadius = (int)(Step * (i + 1));
                numHit = AppleHit - i;
                int actMaxS = (int)Math.Pow(Math.PI * Step * (AppleHit - numHit + 1), 2);

                if (rndS < actMaxS)
                {
                    bHit = true;
                    break;
                }
            }
            if (!bHit)
            {
                numHit = 0;
                minRadius = (int)(Step * AppleHit + 1);
                maxRadius = DiamAll / 2;
            }

            int len = rnd.Next(maxRadius - minRadius) + minRadius;
            double angle = rnd.Next(3600) / 10.0;

            int x = (int)(xCntr + ESpace.EMath.Sin(angle) * len);
            int y = (int)(yCntr + ESpace.EMath.Cos(angle) * len);

            pnt = new Point(x, y);

            // проверка для теста
            double hyp = (int)ESpace.EMath.Hyp(Math.Abs(pnt.X - xCntr), Math.Abs(pnt.Y - yCntr));
            if (hyp > maxRadius) throw new Exception("123");

            return numHit;
        }

        int GenerateNumShot2(out Point pnt)
        {
            // генерим случайные координаты в квадрате DiamAll x DiamAll
            // если координаты выходят за пределы круга DiamAll, генерим еще раз

            double hyp = int.MaxValue;
            pnt = new Point(10, 10);
            while (hyp >= (DiamAll / 2.0))
            {
                int x = rnd.Next(DiamAll);
                int y = rnd.Next(DiamAll);
                pnt = new Point(x, y);
                hyp = (int)ESpace.EMath.Hyp(Math.Abs(x - xCntr), Math.Abs(y - yCntr));
            }

            int ret = AppleHit - (int)(hyp / Step);
            return ret < 0 ? 0 : ret;
        }

        int GenerateNumShot3(out Point pnt)
        {
            // все выпадения чисел с равной вероятностью
            // генерим случайную гипотенузу
            // вычисляем координаты по случайному углу

            double hyp = rnd.Next(DiamAll * 5) / 10.0;

            double angle = rnd.Next(3600) / 10.0;

            int x = (int)(xCntr + ESpace.EMath.Sin(angle) * hyp);
            int y = (int)(yCntr + ESpace.EMath.Cos(angle) * hyp);

            pnt = new Point(x, y);
            int ret = AppleHit - (int)(hyp / Step);
            return ret < 0 ? 0 : ret;
        }

        int delay1 = 300;
        int delay2 = 500;

        private void tmrShot_Tick(object sender, EventArgs e)
        {
            int ms = (int)(DateTime.Now - dtStart).TotalMilliseconds;

            if (ActShot == KolVoDarts)
            {
                if ((ms - (ActShot * delay1 + delay2)) > 0)
                {
                    tmrShot.Stop();
                    Close();
                }
            }
            else if ((ms - ActShot * delay1) > delay1)
            {
                ret[ActShot] = GetShot();
                ActShot++;
                ReDraw();
            }

        }

        private void im_MouseDown(object sender, MouseEventArgs e)
        {
            if (Form1.IsTestShot)
            {
                ret[ActShot] = GetShot();
                ReDraw();
            }
        }


    }
}
